
package models.aaa;

import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.TypedQuery;
import javax.persistence.UniqueConstraint;

import models.Store;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

import play.db.jpa.JPA;

/**
 * 
 * @author laurent@opprecht.info
 */
@Entity
@Table(uniqueConstraints = { @UniqueConstraint(columnNames = { "value" }) })
public class Url {

    public static class Finder {

        public TypedQuery<Url> createQuery(final String sql) {
            TypedQuery<Url> result = JPA.em().createQuery(sql, Url.class);
            return result;
        }

        public TypedQuery<Url> query(final String sql, final Object... parameters) {
            TypedQuery<Url> result = createQuery(sql);
            for (int i = 0; i < parameters.length; i++) {
                result.setParameter(i + 1, parameters[i]);
            }
            return result;
        }

        public TypedQuery<Url> query(final String sql) {
            return query(sql, new Object[] {});
        }

        public Url byUrl(final String url) {
            if (StringUtils.isEmpty(url)) {
                return null;
            }
            String hash = h(url);

            String sql = "SELECT e FROM Url e WHERE e.hash = ? AND e.value = ?";
            List<Url> items = query(sql, hash, url).getResultList();
            for (Url item : items) {
                return item;
            }
            return null;
        }

    }

    public static final Finder find             = new Finder();

    @SuppressWarnings("unused")
    private static final long  serialVersionUID = -994557330115344519L;

    /**
     * Returns existing value if it exists otherwise create it and make it
     * persistent.
     * 
     * Note that the object has to be made persistent in order to preserve
     * identity - that is the same object is returned for each call to the same
     * value. If not made persistent it is not known to the persistent context
     * and searching will return null each time.
     * 
     * An alternative scheme would be to keep a cache of transient objects and
     * check them as well as the persistent storage.
     * 
     * @param url
     * @return
     */
    public static Url get(final String url) {
        if (StringUtils.isEmpty(url)) {
            return null;
        }

        Url result = find.byUrl(url);
        if (result != null) {
            return result;
        }
        result = new Url(url);
        Store.save(result);
        return result;
    }

    public static boolean has(final String url) {
        if (StringUtils.isEmpty(url)) {
            return false;
        }

        return find.byUrl(url) != null;
    }

    public static boolean has(final Url url) {
        if (url == null) {
            return false;
        }
        return has(url.toString());
    }

    public static String h(final String url) {
        return new String(DigestUtils.md5Hex(url));
    }

    @Id
    @GeneratedValue
    private Long     id    = null;
    @Column(length = 255)
    // todo:change that set it to 2024 and remove the unique constraint on value
    protected String value = null;
    protected String hash  = null;

    Url() {
        ;
    }

    Url(final String value) {
        setValue(value);
    }

    /**
     * @return the id
     */
    public Long getId() {
        return id;
    }

    /**
     * @param id
     */
    protected void setId(final Long id) {
        this.id = id;
    }

    public String getValue() {
        return value;
    }

    protected void setValue(String url) {
        url = url == null ? "" : url;
        value = url;
        hash = h(url);
    }

    public String getHash() {
        return hash;
    }

    @Override
    public String toString() {
        if (value == null) {
            return "";
        }
        return value;
    }
}
